package com.ilxqx.framework.system.aop;

import com.ilxqx.framework.system.exception.DataValidationException;
import com.ilxqx.framework.system.exception.SystemException;
import com.ilxqx.framework.system.form.Form;
import com.ilxqx.framework.system.validator.anno.Validate;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * 表单验证
 * @author venus
 */
@Component
@Aspect
@Slf4j
public class FormValidation {

	private final ValidatorFactory validatorFactory;

	@Autowired
	public FormValidation(ValidatorFactory validatorFactory) {
		this.validatorFactory = validatorFactory;
	}

	@Pointcut("execution(* com.ilxqx.framework..controller.*.*(..)) && @annotation(com.ilxqx.framework.system.validator.anno.Validate)")
	public void condition() {}

	@Around("condition()")
	public Object validate(ProceedingJoinPoint joinPoint) throws Throwable {
		if (!(joinPoint.getSignature() instanceof MethodSignature)) {
			// 不是方法代理，抛出错误
			throw new SystemException("只能验证代理的方法");
		}
		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
		// 获取validator
		Validator validator = this.validatorFactory.getValidator();
		Method method = methodSignature.getMethod();
		Class<?>[] groups = method.getDeclaredAnnotation(Validate.class).value();
		Object[] args = joinPoint.getArgs();
		for (Object arg : args) {
			if (arg instanceof Form) {
				Set<ConstraintViolation<Object>> constraintViolations = validator.validate(arg, groups);
				if (constraintViolations.size() > 0) {
					// 有错误
					throw new DataValidationException(constraintViolations.iterator().next().getMessage());
				}
			}
		}
		// 验证通过
		return joinPoint.proceed(args);
	}

}
